/*
	Copyright 2008 Jay Elliott

	This file is part of libemath.

	libemath is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	libemath is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with libemath.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __CQUATERNION_H_
#define __CQUATERNION_H_


#include <cmath>
#include <cstdio>

#include "macros.h"
#include "cMatrix.h"
#include "cPoint3d.h"


namespace emath
{

class cQuaternion
{
public:
	float x, y, z, w;

	inline cQuaternion();
	inline cQuaternion(float wVal, float xVal, float yVal, float zVal);
	inline cQuaternion(cQuaternion const& quat);//copy constructor
	cQuaternion(float angle, cPoint3d axis);//axis-angle

	inline bool operator=(cQuaternion other);
	inline cQuaternion operator+(cQuaternion other);
	inline cQuaternion operator-(cQuaternion other);
	inline void operator+=(cQuaternion other);
	inline void operator-=(cQuaternion other);
	cQuaternion operator*(const cQuaternion& other) const;
	inline 	float GetMagnitude(void);
	inline void normalize(void);
	void GetMatrix(float mat[16]) const;
	cQuaternion inverse(void) const;
	inline cQuaternion conjugate(void) const;

	void GetAxisAngle(float *angle, cPoint3d *axis);

	inline cMatrix GetMatrix(void) const;
};

cQuaternion::cQuaternion()
{
	//do nothing.  This allows for cQuaternions to be put in other classes without using pointers
}

cQuaternion::cQuaternion(float wVal, float xVal, float yVal, float zVal)
{
	x = xVal;
	y = yVal;
	z = zVal;
	w = wVal;
}

cQuaternion::cQuaternion(const emath::cQuaternion &quat)
{
	x = quat.x;
	y = quat.y;
	z = quat.z;
	w = quat.w;
}


cMatrix cQuaternion::GetMatrix(void) const
{
	float mat[16];
	GetMatrix(mat);
	return cMatrix(mat);
}

bool cQuaternion::operator=(emath::cQuaternion other)
{
	x = other.x;
	y = other.y;
	z = other.z;
	w = other.w;

	return true;
}

cQuaternion cQuaternion::operator+(emath::cQuaternion other)
{
	cQuaternion ret;

	ret.x = x + other.x;
	ret.y = y + other.y;
	ret.z = z + other.z;
	ret.w = w + other.w;

	return ret;
}

void cQuaternion::operator+=(cQuaternion other)
{
	*this = *this + other;
}

cQuaternion cQuaternion::operator-(cQuaternion other)
{
	cQuaternion ret;

	ret.x = x - other.x;
	ret.y = y - other.y;
	ret.z = z - other.z;
	ret.w = w - other.w;

	return ret;
}

void cQuaternion::operator-=(cQuaternion other)
{
	*this = *this - other;
}

float cQuaternion::GetMagnitude(void)
{
	return sqrt(x *x + y * y + z * z + w * w);
}

void cQuaternion::normalize(void)
{
	float mag = GetMagnitude();

	w /= mag;
	x /= mag;
	y /= mag;
	z /= mag;
}

cQuaternion cQuaternion::conjugate(void) const
{
	return cQuaternion(w, -x, -y, -z);
}

}

#endif

